package com.alibaba.citrus.ots.sales.plan.facade.msg;

import com.alibaba.acm.shaded.com.alibaba.metrics.StringUtils;
import com.alibaba.citrus.ots.common.annotation.FacadeInvoker;
import com.alibaba.citrus.ots.common.exception.FacadeException;
import com.alibaba.citrus.ots.common.util.CalculatePercentage;
import com.alibaba.citrus.ots.sales.plan.contants.SalesPlanConstants;
import com.alibaba.citrus.ots.sales.plan.dto.api.request.DispatchPlanScItemRequest;
import com.alibaba.citrus.ots.sales.plan.dto.api.request.QueryPlanScItemExtendRequest;
import com.alibaba.citrus.ots.sales.plan.dto.api.request.SalesPlanAdjustDetailBatchQueryRequest;
import com.alibaba.citrus.ots.sales.plan.facade.service.SalesPlanCommonService;
import com.alibaba.citrus.ots.sales.plan.model.enums.SalesPlanAdjustCheckStatusEnum;
import com.alibaba.citrus.ots.sales.plan.model.enums.SalesPlanModelEnum;
import com.alibaba.citrus.ots.sales.plan.model.enums.SalesStatBizTypeEnum;
import com.alibaba.citrus.ots.sales.plan.model.enums.StatPoolTypeEnum;
import com.alibaba.citrus.ots.sales.plan.msg.SalesPlanAdjustResolveMessageConsumer;
import com.alibaba.citrus.ots.sales.plan.repository.SalesPlanAdjustDetailRepository;
import com.alibaba.citrus.ots.sales.plan.repository.SalesPlanRepository;
import com.alibaba.citrus.ots.sales.plan.repository.SalesPlanScItemExtendRepository;
import com.alibaba.citrus.ots.sales.plan.sdo.SalesPlanAdjustDetailSDO;
import com.alibaba.citrus.ots.sales.plan.sdo.SalesPlanSDO;
import com.alibaba.citrus.ots.sales.plan.sdo.SalesPlanScItemExtendSDO;
import com.alibaba.cz.base.tool.log.Log;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.lattice2.epoch.middleware.cache.runtime.service.EpochCacheService;
import com.alibaba.lattice2.epoch.sdk.model.Result;
import com.epoch.app.bcots.contants.BcOtsConstants;
import com.google.common.collect.Lists;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 月度计划调整分解消息
 * @author suqing.tjf
 * @date 2022年01月18日10:20:01
 */
@Component
public class SalesPlanAdjustResolveMessageConsumerImpl implements SalesPlanAdjustResolveMessageConsumer {

    private final Log log = Log.getLogger(SalesPlanAdjustResolveMessageConsumerImpl.class);

    @Resource
    private SalesPlanRepository salesPlanRepository;

    @Resource
    private SalesPlanScItemExtendRepository salesPlanScItemExtendRepository;

    @Resource
    private SalesPlanCommonService salesPlanCommonService;

    @Resource
    private SalesPlanAdjustDetailRepository salesPlanAdjustDetailRepository;

    @Resource
    private EpochCacheService epochCacheService;

    /**
     * 计划调整客户任务分解
     *
     * @param message
     */
    @FacadeInvoker
    @Override
    public Result<Boolean> resolveCustomerTaskForAdjust(String message) {
        log.info("SalesPlanAdjustResolveMessageConsumerImpl.resolveCustomerTaskForAdjust message:" + message);
        DispatchPlanScItemRequest dispatchPlanScItemRequest = null;
        try {
            if (StringUtils.isBlank(message)) {
                log.error("月度计划调整客户任务量分解的消息体为空");
                return Result.success(null, "月度计划调整客户任务量分解接受的消息为空");
            }
            dispatchPlanScItemRequest = JSONObject.parseObject(message, DispatchPlanScItemRequest.class);
            StopWatch stopWatch = new StopWatch();
            stopWatch.start();
            dispatchPlanScItemForAdjustNew(dispatchPlanScItemRequest);
            stopWatch.stop();
            log.info("SalesPlanPublishWriteServiceImpl#dispatchPlanScItemForAdjust planId=" + dispatchPlanScItemRequest.getPlanId() + " elapsed time:" + stopWatch.getTotalTimeMillis() + "ms");
        } catch (Exception e) {
            log.error("SalesPlanPublishWriteServiceImpl#dispatchPlanScItemForAdjust_fail  ", e);
        } finally {
            if (null != dispatchPlanScItemRequest) {
                // 执行完清理缓存
                epochCacheService.remove(BcOtsConstants.REDIS_CACHE_CODE(), Lists.newArrayList(SalesPlanConstants.getDispatchPlanScItemForCustomerAdjustKey(dispatchPlanScItemRequest.getAdjustId())));
            }
        }
        return Result.success(null, "客户调整任务量分解已完成");
    }

    private void dispatchPlanScItemForAdjustNew(DispatchPlanScItemRequest dispatchPlanScItemRequest) {
        // 1、相关参数校验
        String adjustId = dispatchPlanScItemRequest.getAdjustId();
        if (StringUtils.isBlank(adjustId)) {
            throw new FacadeException("OTS-02-004-01-15-018");
        }
        SalesPlanSDO salesPlanSDO = salesPlanCommonService.checkSalesPlan(adjustId);
        Integer planId = salesPlanSDO.getParentId();
        // 2、查询业务单元的调整明细（回复过来），数量级在500以内
        QueryPlanScItemExtendRequest queryPlanScItemExtendRequest = new QueryPlanScItemExtendRequest();
        // 计划id
        queryPlanScItemExtendRequest.setPlanId(Long.valueOf(planId));
        // 业务类型是调整
        queryPlanScItemExtendRequest.setModel(SalesPlanModelEnum.ADJUST_MODEL.getModel());
        // 查询维度是业务单元
        queryPlanScItemExtendRequest.setBizType(SalesStatBizTypeEnum.BUSINESS_UNIT.getBizType());
        // 查询具体的业务单元
        queryPlanScItemExtendRequest.setBizId(salesPlanSDO.getOrgBusinessUnitCode());
        // 货品维度
        queryPlanScItemExtendRequest.setPoolType(Objects.toString(StatPoolTypeEnum.SC_ITEM.getPoolType()));
        // 不同的调整计划
        queryPlanScItemExtendRequest.setModelId(Long.parseLong(adjustId));
        log.info("查询业务单元调整回复量参数：{}", JSON.toJSONString(queryPlanScItemExtendRequest));
        List<SalesPlanScItemExtendSDO> salesPlanScItemExtendSDOList = salesPlanScItemExtendRepository.batchQueryPlanScItemExtend(queryPlanScItemExtendRequest);
        log.info("查询业务单元调整回复量结果：{}", JSON.toJSONString(queryPlanScItemExtendRequest));
        if (CollectionUtils.isEmpty(salesPlanScItemExtendSDOList)) {
            throw new FacadeException("OTS-02-004-01-16-017");
        }
        // 遍历业务单元的调整明细，则按最小货品维度
        for (SalesPlanScItemExtendSDO salesPlanScItemExtendSDO : salesPlanScItemExtendSDOList) {
            // 业务单元调整量
            Integer adjustCount = salesPlanScItemExtendSDO.getAdjustCount();
            // 业务单元上旬调整回复量
            Integer monthFirstAdjustReturnCount = salesPlanScItemExtendSDO.getMonthFirstAdjustReturnCount();
            // 业务单元中旬调整回复量
            Integer monthMiddleAdjustReturnCount = salesPlanScItemExtendSDO.getMonthMiddleAdjustReturnCount();
            // 业务单元下旬调整回复量
            Integer monthLastAdjustReturnCount = salesPlanScItemExtendSDO.getMonthLastAdjustReturnCount();
            // 业务单元计划调整回复量总和
            Integer monthAdjustReturnCount = monthFirstAdjustReturnCount + monthMiddleAdjustReturnCount + monthLastAdjustReturnCount;

            // 业务单元下的每个货品
            // 查询客户货品的调整明细, 咨询产品，产品反馈一个月度计划送达方300以内
            String scItemId = salesPlanScItemExtendSDO.getScItemId();
            SalesPlanAdjustDetailBatchQueryRequest salesPlanAdjustDetailBatchQueryRequest = new SalesPlanAdjustDetailBatchQueryRequest();
            salesPlanAdjustDetailBatchQueryRequest.setAdjustId(adjustId);
            salesPlanAdjustDetailBatchQueryRequest.setScItemId(scItemId);
            salesPlanAdjustDetailBatchQueryRequest.setOrgBusinessUnitCode(salesPlanSDO.getOrgBusinessUnitCode());
            List<SalesPlanAdjustDetailSDO> salesPlanAdjustDetailSDOList = salesPlanAdjustDetailRepository.batchQueryDetail(salesPlanAdjustDetailBatchQueryRequest);

            // 比较业务单元货品调整回复量和货品调整提报量的大小
            // 调整回复量大于调整提报量，按调整提报量向下回复（原调整三旬调整提报量就是调整回复量）
            if (monthAdjustReturnCount >= adjustCount) {
                salesPlanAdjustDetailSDOList.forEach(salesPlanAdjustDetailSDO -> {
                    SalesPlanAdjustDetailSDO editSalesPlanAdjustDetailSDO = SalesPlanAdjustDetailSDO.builder().build();
                    BeanUtils.copyProperties(salesPlanAdjustDetailSDO, editSalesPlanAdjustDetailSDO);
                    // 拿到上旬调整量（准确说叫调整提报量）
                    Integer monthFirstAdjustCount = salesPlanAdjustDetailSDO.getMonthFirstAdjustCount();
                    // 赋值给上旬调整回复量和调整总量
                    editSalesPlanAdjustDetailSDO.setMonthFirstAdjustReturnCount(monthFirstAdjustCount);
                    editSalesPlanAdjustDetailSDO.setMonthFirstAdjustTotalCount(monthFirstAdjustCount);

                    // 拿到中旬调整量（准确说叫调整提报量）
                    Integer monthMiddleAdjustCount = salesPlanAdjustDetailSDO.getMonthMiddleAdjustCount();
                    // 赋值给中旬调整回复量和调整总量
                    editSalesPlanAdjustDetailSDO.setMonthMiddleAdjustReturnCount(monthMiddleAdjustCount);
                    editSalesPlanAdjustDetailSDO.setMonthMiddleAdjustTotalCount(monthMiddleAdjustCount);

                    // 拿到下旬调整量（准确说叫调整提报量）
                    Integer monthLastAdjustCount = salesPlanAdjustDetailSDO.getMonthLastAdjustCount();
                    // 赋值给下旬调整回复量和调整总量
                    editSalesPlanAdjustDetailSDO.setMonthLastAdjustReturnCount(monthLastAdjustCount);
                    editSalesPlanAdjustDetailSDO.setMonthLastAdjustTotalCount(monthLastAdjustCount);

                    // 计算折前任务金额
//                    editSalesPlanAdjustDetailSDO.setBeforeTaskMoney(editSalesPlanAdjustDetailSDO.getTaskCount() * editSalesPlanAdjustDetailSDO.getCostInsuranceFreight());
//                    // 计算折后任务金额
//                    editSalesPlanAdjustDetailSDO.calculateTaskMoney(salesPlanSDO.getEstimateDiscount());
//                    editSalesPlanAdjustDetailSDO.calculateTaskSatisfaction();

                    // 到岸折前金额
                    Integer monthAdjustReturnCountOutbound = editSalesPlanAdjustDetailSDO.getMonthFirstAdjustReturnCount() + editSalesPlanAdjustDetailSDO.getMonthMiddleAdjustReturnCount() + editSalesPlanAdjustDetailSDO.getMonthLastAdjustReturnCount();
                    long outboundPrice = Objects.nonNull(editSalesPlanAdjustDetailSDO.getOutboundPrice()) ? editSalesPlanAdjustDetailSDO.getOutboundPrice() : 0;
                    long beforeMonthOutboundMoney = (editSalesPlanAdjustDetailSDO.getTaskCount() + monthAdjustReturnCountOutbound) * outboundPrice;
                    editSalesPlanAdjustDetailSDO.setBeforeMonthOutboundMoney(beforeMonthOutboundMoney);
                    // 到岸折后金额 到岸折后金额=到岸折前金额*(1-预估价格折扣率)
                    editSalesPlanAdjustDetailSDO.calculateMonthOutboundMoney(salesPlanSDO.getEstimateDiscount());
                    // 更新调整明细表
                    // 折前满足度=（任务量+调整提报量）*货品常规价
                    Integer taskAdjustCount = editSalesPlanAdjustDetailSDO.getTaskCount() + editSalesPlanAdjustDetailSDO.getAdjustCount();
                    Long costInsuranceFreight = editSalesPlanAdjustDetailSDO.getCostInsuranceFreight();
                    // 不落库的折前任务金额
                    long notBeforeContractSatisfactionMoney = taskAdjustCount * costInsuranceFreight;
                    // 落库的折前任务金额
                    long beforeContractSatisfactionMoney = editSalesPlanAdjustDetailSDO.getTaskCount() * costInsuranceFreight;
                    editSalesPlanAdjustDetailSDO.setBeforeTaskMoney(beforeContractSatisfactionMoney);
                    BigDecimal beforeContractSatisfaction = CalculatePercentage.retainTwo(notBeforeContractSatisfactionMoney, editSalesPlanAdjustDetailSDO.getBeforeMonthContractMoney());
                    editSalesPlanAdjustDetailSDO.setBeforeContractSatisfaction(beforeContractSatisfaction);
                    // 折后满足度=（任务量+调整提报量）*货品常规价*（1-预估价格折扣率）
                    BigDecimal multiply = salesPlanSDO.getEstimateDiscount().multiply(new BigDecimal("0.01").setScale(2, RoundingMode.HALF_UP));
                    BigDecimal subtract = new BigDecimal(1).subtract(multiply);
                    BigDecimal ContractSatisfactionMoney = new BigDecimal(taskAdjustCount).multiply(new BigDecimal(costInsuranceFreight)).multiply(subtract);
                    // 折后任务金额
                    editSalesPlanAdjustDetailSDO.calculateTaskMoney(salesPlanSDO.getEstimateDiscount());
                    BigDecimal contractSatisfaction = CalculatePercentage.retainTwoBigDecimal(ContractSatisfactionMoney, new BigDecimal(editSalesPlanAdjustDetailSDO.getMonthContractMoney()));
                    editSalesPlanAdjustDetailSDO.setContractSatisfaction(contractSatisfaction);
                    salesPlanAdjustDetailRepository.edit(editSalesPlanAdjustDetailSDO);
                });
            }
            // 比较业务单元货品调整回复量和货品调整提报量的大小
            // 调整回复量小于调整提报量，按调整回复量根据计算规则向下回复
            else {
                // 2、将调整量正负值的分别筛选出来 (上中下询)
                // 上旬调整量为负的列表
                List<SalesPlanAdjustDetailSDO> firstAdjustNegativeDetail = salesPlanAdjustDetailSDOList.stream()
                        .filter(salesPlanAdjustDetailSDO -> salesPlanAdjustDetailSDO.getMonthFirstAdjustCount() < 0).collect(Collectors.toList());
                // 上旬调整量为正的列表
                List<SalesPlanAdjustDetailSDO> firstAdjustPositiveDetail = salesPlanAdjustDetailSDOList.stream()
                        .filter(salesPlanAdjustDetailSDO -> salesPlanAdjustDetailSDO.getMonthFirstAdjustCount() >= 0).collect(Collectors.toList());

                // 中旬调整量为负的列表
                List<SalesPlanAdjustDetailSDO> middleAdjustNegativeDetail = salesPlanAdjustDetailSDOList.stream()
                        .filter(salesPlanAdjustDetailSDO -> salesPlanAdjustDetailSDO.getMonthMiddleAdjustCount() < 0).collect(Collectors.toList());
                // 中旬调整量为正的列表
                List<SalesPlanAdjustDetailSDO> middleAdjustPositiveDetail = salesPlanAdjustDetailSDOList.stream()
                        .filter(salesPlanAdjustDetailSDO -> salesPlanAdjustDetailSDO.getMonthMiddleAdjustCount() >= 0).collect(Collectors.toList());

                // 下旬调整量为负的列表
                List<SalesPlanAdjustDetailSDO> lastAdjustNegativeDetail = salesPlanAdjustDetailSDOList.stream()
                        .filter(salesPlanAdjustDetailSDO -> salesPlanAdjustDetailSDO.getMonthLastAdjustCount() < 0).collect(Collectors.toList());
                // 下旬调整量为正的列表
                List<SalesPlanAdjustDetailSDO> lastAdjustPositiveDetail = salesPlanAdjustDetailSDOList.stream()
                        .filter(salesPlanAdjustDetailSDO -> salesPlanAdjustDetailSDO.getMonthLastAdjustCount() >= 0).collect(Collectors.toList());

                // 客户上旬调整量负值的和
                Integer firstAdjustNegativeSum = firstAdjustNegativeDetail.stream().mapToInt(SalesPlanAdjustDetailSDO::getMonthFirstAdjustCount).sum();
                // 客户上旬调整量正值的和
                Integer firstAdjustPositiveSum = firstAdjustPositiveDetail.stream().mapToInt(SalesPlanAdjustDetailSDO::getMonthFirstAdjustCount).sum();

                // 客户中旬调整量负值的和
                Integer middleAdjustNegativeSum = middleAdjustNegativeDetail.stream().mapToInt(SalesPlanAdjustDetailSDO::getMonthMiddleAdjustCount).sum();
                // 客户中旬调整量正值的和
                Integer middleAdjustPositiveSum = middleAdjustPositiveDetail.stream().mapToInt(SalesPlanAdjustDetailSDO::getMonthMiddleAdjustCount).sum();

                // 客户下旬调整量负值的和
                Integer lastAdjustNegativeSum = lastAdjustNegativeDetail.stream().mapToInt(SalesPlanAdjustDetailSDO::getMonthLastAdjustCount).sum();
                // 客户下旬调整量正值的和
                Integer lastAdjustPositiveSum = lastAdjustPositiveDetail.stream().mapToInt(SalesPlanAdjustDetailSDO::getMonthLastAdjustCount).sum();

                // 业务单元货品计划调整回复量=0的情况，此时，客户调多少就返回多少
                if (monthAdjustReturnCount == 0) {
                    for (SalesPlanAdjustDetailSDO salesPlanAdjustDetailSDO : salesPlanAdjustDetailSDOList) {
                        SalesPlanAdjustDetailSDO editSalesPlanAdjustDetailSDO = SalesPlanAdjustDetailSDO.builder().build();
                        BeanUtils.copyProperties(salesPlanAdjustDetailSDO, editSalesPlanAdjustDetailSDO);
                        // 拿到上旬调整量（准确说叫调整提报量）
                        Integer monthFirstAdjustCount = salesPlanAdjustDetailSDO.getMonthFirstAdjustCount();
                        // 赋值给上旬调整回复量和调整总量
                        editSalesPlanAdjustDetailSDO.setMonthFirstAdjustReturnCount(monthFirstAdjustCount);
                        editSalesPlanAdjustDetailSDO.setMonthFirstAdjustTotalCount(monthFirstAdjustCount);

                        // 拿到中旬调整量（准确说叫调整提报量）
                        Integer monthMiddleAdjustCount = salesPlanAdjustDetailSDO.getMonthMiddleAdjustCount();
                        // 赋值给上旬调整回复量和调整总量
                        editSalesPlanAdjustDetailSDO.setMonthMiddleAdjustReturnCount(monthMiddleAdjustCount);
                        editSalesPlanAdjustDetailSDO.setMonthMiddleAdjustTotalCount(monthMiddleAdjustCount);

                        // 拿到中旬调整量（准确说叫调整提报量）
                        Integer monthLastAdjustCount = salesPlanAdjustDetailSDO.getMonthLastAdjustCount();
                        // 赋值给上旬调整回复量和调整总量
                        editSalesPlanAdjustDetailSDO.setMonthLastAdjustReturnCount(monthLastAdjustCount);
                        editSalesPlanAdjustDetailSDO.setMonthLastAdjustTotalCount(monthLastAdjustCount);

                     /*   // 计算折前任务金额
                        editSalesPlanAdjustDetailSDO.setBeforeTaskMoney(editSalesPlanAdjustDetailSDO.getTaskCount() * editSalesPlanAdjustDetailSDO.getCostInsuranceFreight());
                        // 计算折后任务金额
                        editSalesPlanAdjustDetailSDO.calculateTaskMoney(salesPlanSDO.getEstimateDiscount());
                        editSalesPlanAdjustDetailSDO.calculateTaskSatisfaction();*/

                        // 到岸折前金额
                        Integer monthAdjustReturnCountOutbound = editSalesPlanAdjustDetailSDO.getMonthFirstAdjustReturnCount() + editSalesPlanAdjustDetailSDO.getMonthMiddleAdjustReturnCount() + editSalesPlanAdjustDetailSDO.getMonthLastAdjustReturnCount();
                        long outboundPrice = Objects.nonNull(editSalesPlanAdjustDetailSDO.getOutboundPrice()) ? editSalesPlanAdjustDetailSDO.getOutboundPrice() : 0;
                        long beforeMonthOutboundMoney = (editSalesPlanAdjustDetailSDO.getTaskCount() + monthAdjustReturnCountOutbound) * outboundPrice;
                        editSalesPlanAdjustDetailSDO.setBeforeMonthOutboundMoney(beforeMonthOutboundMoney);
                        // 到岸折后金额 到岸折后金额=到岸折前金额*(1-预估价格折扣率)
                        editSalesPlanAdjustDetailSDO.calculateMonthOutboundMoney(salesPlanSDO.getEstimateDiscount());
                        // 折前满足度=（任务量+调整提报量）*货品常规价
                        Integer taskAdjustCount = editSalesPlanAdjustDetailSDO.getTaskCount() + editSalesPlanAdjustDetailSDO.getAdjustCount();
                        Long CostInsuranceFreight = editSalesPlanAdjustDetailSDO.getCostInsuranceFreight();
                        // 不落库的折前任务金额
                        long notBeforeContractSatisfactionMoney = taskAdjustCount * CostInsuranceFreight;
                        // 落库的折前任务金额
                        long beforeContractSatisfactionMoney = editSalesPlanAdjustDetailSDO.getTaskCount() * CostInsuranceFreight;
                        // 折前任务金额
                        editSalesPlanAdjustDetailSDO.setBeforeTaskMoney(beforeContractSatisfactionMoney);
                        BigDecimal beforeContractSatisfaction = CalculatePercentage.retainTwo(notBeforeContractSatisfactionMoney, editSalesPlanAdjustDetailSDO.getBeforeMonthContractMoney());
                        editSalesPlanAdjustDetailSDO.setBeforeContractSatisfaction(beforeContractSatisfaction);
                        // 折后满足度=（任务量+调整提报量）*货品常规价*（1-预估价格折扣率）
                        BigDecimal multiply = salesPlanSDO.getEstimateDiscount().multiply(new BigDecimal("0.01").setScale(2, RoundingMode.HALF_UP));
                        BigDecimal subtract = new BigDecimal(1).subtract(multiply);
                        BigDecimal ContractSatisfactionMoney = new BigDecimal(taskAdjustCount).multiply(new BigDecimal(CostInsuranceFreight)).multiply(subtract);
                        // 折后任务金额
                        editSalesPlanAdjustDetailSDO.calculateTaskMoney(salesPlanSDO.getEstimateDiscount());
                        BigDecimal contractSatisfaction = CalculatePercentage.retainTwoBigDecimal(ContractSatisfactionMoney, new BigDecimal(editSalesPlanAdjustDetailSDO.getMonthContractMoney()));
                        editSalesPlanAdjustDetailSDO.setContractSatisfaction(contractSatisfaction);
                        // 更新调整明细表
                        salesPlanAdjustDetailRepository.edit(editSalesPlanAdjustDetailSDO);
                    }
                }
                // 业务单元货品计划调整回复量>0的情况
                else if (monthAdjustReturnCount > 0) {
                    // 业务单元回复值   业务单元货品计划调整回复量-（客户调整量负值）
                    // 业务单元上旬实际回复值
                    Integer monthFirstAdjustTheoryReturnCount = monthFirstAdjustReturnCount - firstAdjustNegativeSum;
                    // 业务单元中旬实际回复值
                    Integer monthMiddleAdjustTheoryReturnCount = monthMiddleAdjustReturnCount - middleAdjustNegativeSum;
                    // 业务单元下旬实际回复值
                    Integer monthLastAdjustTheoryReturnCount = monthLastAdjustReturnCount - lastAdjustNegativeSum;
                    // 遍历客户调整明细
                    for (SalesPlanAdjustDetailSDO salesPlanAdjustDetailSDO : salesPlanAdjustDetailSDOList) {

                        SalesPlanAdjustDetailSDO editSalesPlanAdjustDetailSDO = SalesPlanAdjustDetailSDO.builder().build();
                        BeanUtils.copyProperties(salesPlanAdjustDetailSDO, editSalesPlanAdjustDetailSDO);
                        // 上旬调整提报量
                        Integer monthFirstAdjustCount = salesPlanAdjustDetailSDO.getMonthFirstAdjustCount();
                        // 计算上旬调整回复量
                        Integer firstAdjustReturnCount = getMonthAdjustReturnCountDefaultNegative(monthFirstAdjustCount, firstAdjustPositiveSum, monthFirstAdjustTheoryReturnCount);
                        editSalesPlanAdjustDetailSDO.setMonthFirstAdjustReturnCount(firstAdjustReturnCount);
                        editSalesPlanAdjustDetailSDO.setMonthFirstAdjustTotalCount(firstAdjustReturnCount);

                        // 中旬调整提报量
                        Integer monthMiddleAdjustCount = salesPlanAdjustDetailSDO.getMonthMiddleAdjustCount();
                        // 计算中旬调整回复量
                        Integer middleAdjustReturnCount = getMonthAdjustReturnCountDefaultNegative(monthMiddleAdjustCount, middleAdjustPositiveSum, monthMiddleAdjustTheoryReturnCount);
                        editSalesPlanAdjustDetailSDO.setMonthMiddleAdjustReturnCount(middleAdjustReturnCount);
                        editSalesPlanAdjustDetailSDO.setMonthMiddleAdjustTotalCount(middleAdjustReturnCount);

                        // 下旬调整提报量
                        Integer monthLastAdjustCount = salesPlanAdjustDetailSDO.getMonthLastAdjustCount();
                        // 计算下旬调整回复量
                        Integer lastAdjustReturnCount = getMonthAdjustReturnCountDefaultNegative(monthLastAdjustCount, lastAdjustPositiveSum, monthLastAdjustTheoryReturnCount);
                        editSalesPlanAdjustDetailSDO.setMonthLastAdjustReturnCount(lastAdjustReturnCount);
                        editSalesPlanAdjustDetailSDO.setMonthLastAdjustTotalCount(lastAdjustReturnCount);

                        /*// 计算折前任务金额
                        editSalesPlanAdjustDetailSDO.setBeforeTaskMoney(editSalesPlanAdjustDetailSDO.getTaskCount() * editSalesPlanAdjustDetailSDO.getCostInsuranceFreight());
                        // 计算折后任务金额
                        editSalesPlanAdjustDetailSDO.calculateTaskMoney(salesPlanSDO.getEstimateDiscount());
                        editSalesPlanAdjustDetailSDO.calculateTaskSatisfaction();*/
                        // 到岸折前金额
                        Integer monthAdjustReturnCountOutbound = editSalesPlanAdjustDetailSDO.getMonthFirstAdjustReturnCount() + editSalesPlanAdjustDetailSDO.getMonthMiddleAdjustReturnCount() + editSalesPlanAdjustDetailSDO.getMonthLastAdjustReturnCount();
                        long outboundPrice = Objects.nonNull(editSalesPlanAdjustDetailSDO.getOutboundPrice()) ? editSalesPlanAdjustDetailSDO.getOutboundPrice() : 0;
                        long beforeMonthOutboundMoney = (editSalesPlanAdjustDetailSDO.getTaskCount() + monthAdjustReturnCountOutbound) * outboundPrice;
                        editSalesPlanAdjustDetailSDO.setBeforeMonthOutboundMoney(beforeMonthOutboundMoney);
                        // 到岸折后金额 到岸折后金额=到岸折前金额*(1-预估价格折扣率)
                        editSalesPlanAdjustDetailSDO.calculateMonthOutboundMoney(salesPlanSDO.getEstimateDiscount());
                        // 折前满足度=（任务量+调整提报量）*货品常规价
                        Integer taskAdjustCount = editSalesPlanAdjustDetailSDO.getTaskCount() + editSalesPlanAdjustDetailSDO.getAdjustCount();
                        Long CostInsuranceFreight = editSalesPlanAdjustDetailSDO.getCostInsuranceFreight();
                        // 不落库的折前任务金额
                        long notBeforeContractSatisfactionMoney = taskAdjustCount * CostInsuranceFreight;
                        // 落库的折前任务金额
                        long beforeContractSatisfactionMoney = editSalesPlanAdjustDetailSDO.getTaskCount() * CostInsuranceFreight;
                        // 折前任务金额
                        editSalesPlanAdjustDetailSDO.setBeforeTaskMoney(beforeContractSatisfactionMoney);
                        BigDecimal beforeContractSatisfaction = CalculatePercentage.retainTwo(notBeforeContractSatisfactionMoney, editSalesPlanAdjustDetailSDO.getBeforeMonthContractMoney());
                        editSalesPlanAdjustDetailSDO.setBeforeContractSatisfaction(beforeContractSatisfaction);
                        // 折后满足度=（任务量+调整提报量）*货品常规价*（1-预估价格折扣率）
                        BigDecimal multiply = salesPlanSDO.getEstimateDiscount().multiply(new BigDecimal("0.01").setScale(2, RoundingMode.HALF_UP));
                        BigDecimal subtract = new BigDecimal(1).subtract(multiply);
                        BigDecimal ContractSatisfactionMoney = new BigDecimal(taskAdjustCount).multiply(new BigDecimal(CostInsuranceFreight)).multiply(subtract);
                        // 折后任务金额
                        editSalesPlanAdjustDetailSDO.calculateTaskMoney(salesPlanSDO.getEstimateDiscount());
                        BigDecimal contractSatisfaction = CalculatePercentage.retainTwoBigDecimal(ContractSatisfactionMoney, new BigDecimal(editSalesPlanAdjustDetailSDO.getMonthContractMoney()));
                        editSalesPlanAdjustDetailSDO.setContractSatisfaction(contractSatisfaction);
                        // 更新调整明细表
                        salesPlanAdjustDetailRepository.edit(editSalesPlanAdjustDetailSDO);
                    }
                }
                // 业务单元货品计划调整回复量<0的情况
                else {
                    // 业务单元回复值   业务单元货品计划调整回复量-（客户调整量正值）
                    // 业务单元上旬实际回复值
                    Integer monthFirstAdjustTheoryReturnCount = monthFirstAdjustReturnCount - firstAdjustPositiveSum;
                    // 业务单元中旬实际回复值
                    Integer monthMiddleAdjustTheoryReturnCount = monthMiddleAdjustReturnCount - middleAdjustPositiveSum;
                    // 业务单元下旬实际回复值
                    Integer monthLastAdjustTheoryReturnCount = monthLastAdjustReturnCount - lastAdjustPositiveSum;
                    // 遍历客户调整明细
                    for (SalesPlanAdjustDetailSDO salesPlanAdjustDetailSDO : salesPlanAdjustDetailSDOList) {
                        SalesPlanAdjustDetailSDO editSalesPlanAdjustDetailSDO = SalesPlanAdjustDetailSDO.builder().build();
                        BeanUtils.copyProperties(salesPlanAdjustDetailSDO, editSalesPlanAdjustDetailSDO);
                        // 上旬调整提报量
                        Integer monthFirstAdjustCount = salesPlanAdjustDetailSDO.getMonthFirstAdjustCount();
                        // 计算上旬调整回复量
                        Integer firstAdjustReturnCount = getMonthAdjustReturnCountDefaultPositive(monthFirstAdjustCount, firstAdjustNegativeSum, monthFirstAdjustTheoryReturnCount);
                        editSalesPlanAdjustDetailSDO.setMonthFirstAdjustReturnCount(firstAdjustReturnCount);
                        editSalesPlanAdjustDetailSDO.setMonthFirstAdjustTotalCount(firstAdjustReturnCount);

                        // 中旬调整提报量
                        Integer monthMiddleAdjustCount = salesPlanAdjustDetailSDO.getMonthMiddleAdjustCount();
                        // 计算中旬调整回复量
                        Integer middleAdjustReturnCount = getMonthAdjustReturnCountDefaultPositive(monthMiddleAdjustCount, middleAdjustNegativeSum, monthMiddleAdjustTheoryReturnCount);
                        editSalesPlanAdjustDetailSDO.setMonthMiddleAdjustReturnCount(middleAdjustReturnCount);
                        editSalesPlanAdjustDetailSDO.setMonthMiddleAdjustTotalCount(middleAdjustReturnCount);

                        // 下旬调整提报量
                        Integer monthLastAdjustCount = salesPlanAdjustDetailSDO.getMonthLastAdjustCount();
                        // 计算下旬调整回复量
                        Integer lastAdjustReturnCount = getMonthAdjustReturnCountDefaultPositive(monthLastAdjustCount, lastAdjustNegativeSum, monthLastAdjustTheoryReturnCount);
                        editSalesPlanAdjustDetailSDO.setMonthLastAdjustReturnCount(lastAdjustReturnCount);
                        editSalesPlanAdjustDetailSDO.setMonthLastAdjustTotalCount(lastAdjustReturnCount);

                        /*// 计算折前任务金额
                        editSalesPlanAdjustDetailSDO.setBeforeTaskMoney(editSalesPlanAdjustDetailSDO.getTaskCount() * editSalesPlanAdjustDetailSDO.getCostInsuranceFreight());
                        // 计算折后任务金额
                        editSalesPlanAdjustDetailSDO.calculateTaskMoney(salesPlanSDO.getEstimateDiscount());
                        editSalesPlanAdjustDetailSDO.calculateTaskSatisfaction();*/
                        // 到岸折前金额
                        Integer monthAdjustReturnCountOutbound = editSalesPlanAdjustDetailSDO.getMonthFirstAdjustReturnCount() + editSalesPlanAdjustDetailSDO.getMonthMiddleAdjustReturnCount() + editSalesPlanAdjustDetailSDO.getMonthLastAdjustReturnCount();
                        long outboundPrice = Objects.nonNull(editSalesPlanAdjustDetailSDO.getOutboundPrice()) ? editSalesPlanAdjustDetailSDO.getOutboundPrice() : 0;
                        long beforeMonthOutboundMoney = (editSalesPlanAdjustDetailSDO.getTaskCount() + monthAdjustReturnCountOutbound) * outboundPrice;
                        editSalesPlanAdjustDetailSDO.setBeforeMonthOutboundMoney(beforeMonthOutboundMoney);
                        // 到岸折后金额 到岸折后金额=到岸折前金额*(1-预估价格折扣率)
                        editSalesPlanAdjustDetailSDO.calculateMonthOutboundMoney(salesPlanSDO.getEstimateDiscount());
                        // 折前满足度=（任务量+调整提报量）*货品常规价
                        Integer taskAdjustCount = editSalesPlanAdjustDetailSDO.getTaskCount() + editSalesPlanAdjustDetailSDO.getAdjustCount();
                        Long CostInsuranceFreight = editSalesPlanAdjustDetailSDO.getCostInsuranceFreight();
                        // 不落库的折前任务金额
                        long notBeforeContractSatisfactionMoney = taskAdjustCount * CostInsuranceFreight;
                        // 落库的折前任务金额
                        long beforeContractSatisfactionMoney = editSalesPlanAdjustDetailSDO.getTaskCount() * CostInsuranceFreight;
                        // 折前任务金额
                        editSalesPlanAdjustDetailSDO.setBeforeTaskMoney(beforeContractSatisfactionMoney);
                        BigDecimal beforeContractSatisfaction = CalculatePercentage.retainTwo(notBeforeContractSatisfactionMoney, editSalesPlanAdjustDetailSDO.getBeforeMonthContractMoney());
                        editSalesPlanAdjustDetailSDO.setBeforeContractSatisfaction(beforeContractSatisfaction);
                        // 折后满足度=（任务量+调整提报量）*货品常规价*（1-预估价格折扣率）
                        BigDecimal multiply = salesPlanSDO.getEstimateDiscount().multiply(new BigDecimal("0.01").setScale(2, BigDecimal.ROUND_HALF_UP));
                        BigDecimal subtract = new BigDecimal(1).subtract(multiply);
                        BigDecimal ContractSatisfactionMoney = new BigDecimal(taskAdjustCount).multiply(new BigDecimal(CostInsuranceFreight)).multiply(subtract);
                        // 折后任务金额
                        editSalesPlanAdjustDetailSDO.calculateTaskMoney(salesPlanSDO.getEstimateDiscount());
                        BigDecimal contractSatisfaction = CalculatePercentage.retainTwoBigDecimal(ContractSatisfactionMoney, new BigDecimal(editSalesPlanAdjustDetailSDO.getMonthContractMoney()));
                        editSalesPlanAdjustDetailSDO.setContractSatisfaction(contractSatisfaction);
                        // 更新调整明细表
                        salesPlanAdjustDetailRepository.edit(editSalesPlanAdjustDetailSDO);
                    }
                }
            }
        }
        // 查询调整id
        // 生成客户调整回复量时，修改checkStatus的状态
        SalesPlanSDO updateCheckStatusSalesPlanSDO = new SalesPlanSDO();
        updateCheckStatusSalesPlanSDO.setCheckStatus(SalesPlanAdjustCheckStatusEnum.DECOMPOSE_ADJUST_RETURN.getCode());
        updateCheckStatusSalesPlanSDO.setId(Long.valueOf(adjustId));
        updateCheckStatusSalesPlanSDO.setGmtModified(new Date());
        salesPlanRepository.editSalesPlan(updateCheckStatusSalesPlanSDO);
    }

    /**
     * 计算上中下询的客户调整明细   （客户调整量为负值，默认回复）
     *
     * @param monthAdjustCount             各三询的调整提报量
     * @param adjustPositiveSum            各三询的调整提报量正值汇总
     * @param monthAdjustTheoryReturnCount 业务单元的三旬实际回复值
     * @return
     */
    private Integer getMonthAdjustReturnCountDefaultNegative(Integer monthAdjustCount, Integer adjustPositiveSum, Integer monthAdjustTheoryReturnCount) {
        int monthFirstAdjustReturnCount;
        // 判断调整提报量的正负
        // 调整提报量为负，按原值优先回复
        if (monthAdjustCount <= 0) {
            monthFirstAdjustReturnCount = monthAdjustCount;
        }
        // 上旬调整提报量是正值
        else {
            // 计算上旬理论回复占比  客户货品调整量正值/客户货品调整量正值的汇总
            BigDecimal bigDecimal = CalculatePercentage.retainTwo(monthAdjustCount.longValue(), adjustPositiveSum.longValue());
            BigDecimal adjustRate = bigDecimal.multiply(new BigDecimal("0.01")).setScale(2, RoundingMode.HALF_UP);
            // 计算上旬客户理论回复量   业务单元实际回复量*理论回复占比
            monthFirstAdjustReturnCount = new BigDecimal(monthAdjustTheoryReturnCount).multiply(adjustRate).setScale(0, RoundingMode.HALF_UP).intValue();
        }
        return monthFirstAdjustReturnCount;
    }

    /**
     * 计算上中下询的客户调整明细   （客户调整量为正值，默认回复）
     *
     * @param monthAdjustCount             各三询的调整提报量
     * @param adjustNegativeSum            各三询的调整提报量负值汇总
     * @param monthAdjustTheoryReturnCount 业务单元的三旬实际回复值
     * @return
     */
    private Integer getMonthAdjustReturnCountDefaultPositive(Integer monthAdjustCount, Integer adjustNegativeSum, Integer monthAdjustTheoryReturnCount) {
        int monthFirstAdjustReturnCount;
        // 判断调整提报量的正负
        // 调整提报量为负
        if (monthAdjustCount <= 0) {
            // 计算上旬理论回复占比  客户货品调整量正值/客户货品调整量正值的汇总
            BigDecimal bigDecimal = CalculatePercentage.retainTwo(monthAdjustCount.longValue(), adjustNegativeSum.longValue());
            BigDecimal adjustRate = bigDecimal.multiply(new BigDecimal("0.01")).setScale(2, RoundingMode.HALF_UP);
            // 计算上旬客户理论回复量   业务单元实际回复量*理论回复占比
            monthFirstAdjustReturnCount = new BigDecimal(monthAdjustTheoryReturnCount).multiply(adjustRate).setScale(0, RoundingMode.HALF_UP).intValue();
        }
        // 上旬调整提报量是正值，按原值默认回复
        else {
            monthFirstAdjustReturnCount = monthAdjustCount;
        }
        return monthFirstAdjustReturnCount;
    }
}
